package com.bkgy.modularbx.coil_prod_stats.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bkgy.commom.model.QueryDTO;
import com.bkgy.modularbx.coil_prod_stats.domain.TCoilProductionStats;
import com.bkgy.modularbx.coil_prod_stats.dto.*;
import com.bkgy.modularbx.coil_prod_stats.mapper.TCoilProductionStatsMapper;
import com.bkgy.modularbx.coil_prod_stats.service.TCoilProductionStatsService;
import com.bkgy.sys.common.entity.ResultData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author dell
* @description 针对表【T_COIL_PRODUCTION_STATS】的数据库操作Service实现
* @createDate 2025-06-10 10:06:27
*/
@Slf4j
@Service
public class TCoilProductionStatsServiceImpl extends ServiceImpl<TCoilProductionStatsMapper, TCoilProductionStats>
    implements TCoilProductionStatsService {

    // 常量集中管理
    private static final String REASON_QUALITY = "质量缺陷原因";
    private static final String REASON_YIELD = "成材率原因";
    private static final String REASON_WEIGHT = "原料重量不符";

    private static final String MSG_LEFT_CREW_FMT = "请对应机组（%s）关注控制%s";
    private static final String MSG_LEFT_MANAGE = "请运营管理者与制造端/销售端协同改善";
    private static final String MSG_LEFT_FALLBACK = "请重点关注此缺陷原因";
    private static final String MSG_RIGHT_FMT = "%s损失重量约为%s吨，损失比例约达到%s%%，请重点关注此缺陷原因";
    
    /**
     * 前端产线代码到后端表字段的映射
     */
    private static final Map<String, String> LINE_CODE_MAP = new HashMap<>();
    
    static {
        LINE_CODE_MAP.put("TCM2280", "TCM2280");
        LINE_CODE_MAP.put("CAL2150", "CAL2150");
        LINE_CODE_MAP.put("CAL1630", "CAL1630");
        LINE_CODE_MAP.put("CGL1870", "CGL1870");
        LINE_CODE_MAP.put("RCL2150", "RECOIL1");
        LINE_CODE_MAP.put("RCL1630", "RECOIL2");
        LINE_CODE_MAP.put("RCL1870", "RECOIL3");
    }

    @Resource
    private TCoilProductionStatsMapper coilProductionStatsMapper;

    @Override
    public ResultData<List<CoilStatsResultDTO>> statsSteelGradeBySpec(CoilStatsQueryDTO queryDTO) {
        if (queryDTO == null) {
            return ResultData.ResultDataFaultSelf("查询条件不能为空", null);
        }
        
        // 计算时间范围和时间标记
        String startDate = null;
        String endDate = null;

        // 根据时间类型计算日期范围
        switch (queryDTO.getTimeType()) {
            case 1: // 按月统计（上个月整月）
                // 计算上个月的第一天和最后一天
                Date lastMonthFirstDay = DateUtil.beginOfMonth(DateUtil.lastMonth());
                Date lastMonthLastDay = DateUtil.endOfMonth(DateUtil.lastMonth());
                Date lastMonthLastDayEnd = DateUtil.endOfDay(lastMonthLastDay);
                startDate = DateUtil.format(lastMonthFirstDay, "yyyy-MM-dd");
                endDate = DateUtil.format(lastMonthLastDayEnd, "yyyy-MM-dd HH:mm:ss");
                break;
                
            case 0: // 按日统计（昨天）
                // 获取昨天的日期
                Date yesterdayDate = DateUtil.yesterday();
                Date yesterdayEnd = DateUtil.endOfDay(yesterdayDate);
                startDate = DateUtil.format(yesterdayDate, "yyyy-MM-dd");
                endDate = DateUtil.format(yesterdayEnd, "yyyy-MM-dd HH:mm:ss");
                break;
                
            case 2: // 按时间范围统计
                startDate = queryDTO.getStartDate();
                endDate = queryDTO.getEndDate();
                // 验证日期范围
                if (startDate == null || endDate == null) {
                    return ResultData.ResultDataFaultSelf("时间范围不能为空", null);
                }
                // 将结束日期转换为23:59:59
                Date endDateObj = DateUtil.parse(endDate);
                Date endDateEnd = DateUtil.endOfDay(endDateObj);
                endDate = DateUtil.format(endDateEnd, "yyyy-MM-dd HH:mm:ss");
                break;
                
            default:
                return ResultData.ResultDataFaultSelf("不支持的时间类型", null);
        }
        // 产线代码转换：前端传值到后端表字段的映射
        String backendLineCode = convertLineCode(queryDTO.getLineCode());
        
        // 统一用statsByTimeRange方法查询
        List<CoilStatsResultDTO> resultList = coilProductionStatsMapper.statsByTimeRange(
                backendLineCode,
                startDate,
                endDate
        );

        return ResultData.ResultDataSuccess(resultList, resultList.size());
    }
    @Override
    public ResultData<DefectReasonResultDTO.DefectReasonResponse> statsDefectReasonLoss(DefectReasonQueryDTO queryDTO) {
        if (queryDTO == null) {
            return ResultData.ResultDataFaultSelf("查询条件不能为空", null);
        }
        // 产线代码转换
        queryDTO.setLineCode(convertLineCode(queryDTO.getLineCode()));
        
        // 如果跟踪编号列表为空，则查询全部数据
        List<DefectReasonResultDTO> resultList = new ArrayList<>();
        if (StringUtils.isEmpty(queryDTO.getTrackIndocnos())){
            resultList = statsAllDefectReasonLoss(queryDTO);
        }else {
            resultList = coilProductionStatsMapper.statsDefectReason(queryDTO);

        }
        //排除未知原因（暂时无法归纳 后续归纳）
        List<DefectReasonResultDTO> collect = resultList.stream()
                .filter(t -> t.getDefectReason() != null)
                .collect(Collectors.toList());

        DefectReasonResultDTO.DefectReasonResponse resp = new DefectReasonResultDTO.DefectReasonResponse();
        resp.setResultList(collect);

        if (!CollectionUtils.isEmpty(collect)) {
            // 已按 lossRatio 降序，直接取第一条
            DefectReasonResultDTO main = resultList.get(0);
            setSplitSuggestions(resp, main);
        }

        return ResultData.ResultDataSuccess(resp, resultList == null ? 0 : resultList.size());
    }

    // 抽取生成左右侧切分建议（正确位置）
    private void setSplitSuggestions(DefectReasonResultDTO.DefectReasonResponse resp, DefectReasonResultDTO main) {
        String reason = main.getDefectReason() == null ? "" : main.getDefectReason();
        String crewsRaw = main.getCrews() == null ? "" : main.getCrews();
        String crews = dedupCrews(crewsRaw);

        BigDecimal lw = main.getLossWeight() == null ? BigDecimal.ZERO : main.getLossWeight();
        BigDecimal lr = main.getLossRatio() == null ? BigDecimal.ZERO : main.getLossRatio();
        String lwStr = lw.stripTrailingZeros().toPlainString();
        String lrStr = lr.stripTrailingZeros().toPlainString();

        String leftSuggestion;
        if (REASON_QUALITY.equals(reason) || REASON_YIELD.equals(reason)) {
            leftSuggestion = String.format(MSG_LEFT_CREW_FMT, crews, reason);
        } else if (REASON_WEIGHT.equals(reason)) {
            leftSuggestion = MSG_LEFT_MANAGE;
        } else {
            leftSuggestion = MSG_LEFT_FALLBACK;
        }

        String rightSuggestion = String.format(MSG_RIGHT_FMT, reason, lwStr, lrStr);

        resp.setLeftSplitSuggestion(leftSuggestion);
        resp.setRightSplitSuggestion(rightSuggestion);
    }

    // crews
    private static String dedupCrews(String crews) {
        if (crews == null || crews.trim().isEmpty()) {
            return "";
        }
        return Arrays.stream(crews.split("[,]"))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .distinct()
                .collect(Collectors.joining(","));
    }

    //@Override
    private List<DefectReasonResultDTO> statsAllDefectReasonLoss(DefectReasonQueryDTO queryDTO) {

        // 计算时间范围和时间标记
        String startDate = null;
        String endDate = null;

        // 根据时间类型计算日期范围
        switch (queryDTO.getTimeType()) {
            case 1: // 按月统计（上个月整月）
                // 使用Hutool计算上个月的第一天和最后一天
                Date lastMonthFirstDay = DateUtil.beginOfMonth(DateUtil.lastMonth());
                Date lastMonthLastDay = DateUtil.endOfMonth(DateUtil.lastMonth());
                Date lastMonthLastDayEnd = DateUtil.endOfDay(lastMonthLastDay);
                startDate = DateUtil.format(lastMonthFirstDay, "yyyy-MM-dd");
                endDate = DateUtil.format(lastMonthLastDayEnd, "yyyy-MM-dd HH:mm:ss");
                break;
                
            case 0: // 按日统计（昨天）
                // 使用Hutool获取昨天的日期
                Date yesterdayDate = DateUtil.yesterday();
                Date yesterdayEnd = DateUtil.endOfDay(yesterdayDate);
                startDate = DateUtil.format(yesterdayDate, "yyyy-MM-dd");
                endDate = DateUtil.format(yesterdayEnd, "yyyy-MM-dd HH:mm:ss");
                break;
                
            case 2: // 按时间范围统计
                startDate = queryDTO.getStartDate();
                endDate = queryDTO.getEndDate();
                if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) {
                    Date endDateObj = DateUtil.parse(endDate);
                    Date endDateEnd = DateUtil.endOfDay(endDateObj);
                    endDate = DateUtil.format(endDateEnd, "yyyy-MM-dd HH:mm:ss");
                }
                break;
                
            default:
                // 不支持的时间类型，返回空列表
                return Collections.EMPTY_LIST;
        }
        // 统一使用statsDefectReasonByTimeRange方法查询
        List<DefectReasonResultDTO> resultList = coilProductionStatsMapper.statsDefectReasonByTimeRange(
                queryDTO.getLineCode(),
                queryDTO.getDefectReason(),
                queryDTO.getDefectReasonCode(),
                startDate,
                endDate
        );
        return resultList;
    }
    
    @Override
    public ResultData<List<MaterialWeightRangeResultDTO>> statsMaterialWeightRange(QueryDTO<MaterialWeightRangeQueryDTO> queryDTO) {
        if (queryDTO == null || queryDTO.getDto() == null) {
            return ResultData.ResultDataFaultSelf("查询条件不能为空", null);
        }

        MaterialWeightRangeQueryDTO dto = queryDTO.getDto();
        // 产线代码转换
        dto.setLineCode(convertLineCode(dto.getLineCode()));
        Page page = new Page<>(queryDTO.getPage().getPageIndex(), queryDTO.getPage().getPageSize());
        
        try {
            IPage<MaterialWeightRangeResultDTO> pageResult;
            
            // 根据统计时间类型执行不同的统计方法
            switch (dto.getTimeType()) {
                case 1: // 按月统计（上个月整月）
                    pageResult = coilProductionStatsMapper.statsMaterialWeightRangeLastMonth(
                            page,
                            dto.getLineCode(),
                            dto.getSteelGrade()
                    );
                    break;
                    
                case 0: // 按日统计（昨天）
                    pageResult = coilProductionStatsMapper.statsMaterialWeightRangeYesterday(
                            page,
                            dto.getLineCode(),
                            dto.getSteelGrade()
                    );
                    break;
                    
                case 2: // 按时间范围统计
                    pageResult = coilProductionStatsMapper.statsMaterialWeightRangeByTimeRange(
                            page,
                            dto.getLineCode(),
                            dto.getSteelGrade(),
                            dto.getStartDate(),
                            dto.getEndDate()
                    );
                    break;
                    
                default:
                    // 如果没有指定时间类型，使用原有的分页查询逻辑（兼容性）
                    pageResult = coilProductionStatsMapper.statsMaterialWeightRange(
                            page,
                            dto.getSteelGrade(),
                            dto.getStartDate(),
                            dto.getEndDate()
                    );
                    break;
            }
            // 批量查询并合并平均分卷数（历史统计）
            if (pageResult != null && pageResult.getRecords() != null && !pageResult.getRecords().isEmpty()) {
                mergeAvgCoilRecords(pageResult.getRecords());
            }
            
            return ResultData.ResultDataSuccess(pageResult);
            
        } catch (Exception e) {
            log.error("查询失败：系统异常", e);
            return ResultData.ResultDataFaultSelf("查询失败：系统异常", null);
        }
    }

    /**
     * 批量查询并合并平均分卷数到记录列表
     */
    private void mergeAvgCoilRecords(List<MaterialWeightRangeResultDTO> records) {
        if (records == null || records.isEmpty()) {
            return;
        }
        // 去重分组键
        Map<String, MaterialWeightRangeResultDTO> uniq = new LinkedHashMap<>();
        for (MaterialWeightRangeResultDTO r : records) {
            uniq.put(buildGroupKey(r.getSteelGrade(), r.getWidClass(), r.getThkClass(), r.getOrderwtMinMax()), r);
        }
        List<MaterialWeightRangeResultDTO> groupKeys = new ArrayList<>(uniq.values());

        List<Map<String, Object>> maps = coilProductionStatsMapper.batchGetAvgCoilRecordsByGroups(groupKeys);

        // 转换为 Map<GROUPKEY, BigDecimal>
        Map<String, BigDecimal> avgMap = (maps == null || maps.isEmpty()) ? Collections.emptyMap() :
                maps.stream()
                        .filter(Objects::nonNull)
                        .collect(Collectors.toMap(
                                row ->  row.getOrDefault("GROUPKEY", "").toString().trim(),
                                row -> new BigDecimal(row.getOrDefault("AVGCOILRECORDS", "0").toString().trim())));

        // 并行合并结果
        Map<String, BigDecimal> finalAvgMap = avgMap;
        records.parallelStream().forEach(r -> {
            String key = buildGroupKey(r.getSteelGrade(), r.getWidClass(), r.getThkClass(), r.getOrderwtMinMax());
            r.setAvgCoilRecords(finalAvgMap.getOrDefault(key, BigDecimal.ZERO));
        });
    }

    /**
     * 构建分组键
     */
    private String buildGroupKey(String steelGrade, String widClass, String thkClass, String orderwtMinMax) {
        return String.join("|",
                steelGrade == null ? "" : steelGrade,
                widClass == null ? "" : widClass,
                thkClass == null ? "" : thkClass,
                orderwtMinMax == null ? "" : orderwtMinMax);
    }
    
    /**
     * 产线代码转换：前端传值到后端表字段的映射
     */
    private String convertLineCode(String frontendLineCode) {
        if (frontendLineCode == null || frontendLineCode.trim().isEmpty()) {
            return frontendLineCode;
        }
        
        String trimmedCode = frontendLineCode.trim();
        return LINE_CODE_MAP.getOrDefault(trimmedCode, trimmedCode);
    }
}




